package com.ragdollcat.thirdaicodegenerate.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.ragdollcat.thirdaicodegenerate.constants.UserConstant;
import com.ragdollcat.thirdaicodegenerate.enums.ChatHistoryMessageTypeEnum;
import com.ragdollcat.thirdaicodegenerate.exception.ErrorCode;
import com.ragdollcat.thirdaicodegenerate.exception.ThrowUtils;
import com.ragdollcat.thirdaicodegenerate.mapper.ChatHistoryMapper;
import com.ragdollcat.thirdaicodegenerate.model.dto.chathistory.ChatHistoryQueryRequest;
import com.ragdollcat.thirdaicodegenerate.model.entity.App;
import com.ragdollcat.thirdaicodegenerate.model.entity.ChatHistory;
import com.ragdollcat.thirdaicodegenerate.model.entity.User;
import com.ragdollcat.thirdaicodegenerate.service.AppService;
import com.ragdollcat.thirdaicodegenerate.service.ChatHistoryService;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 对话历史 服务层实现。
 *
 * @author Administrator
 */
@Slf4j
@Service
public class ChatHistoryServiceImpl extends ServiceImpl<ChatHistoryMapper, ChatHistory> implements ChatHistoryService {

    @Resource
    private AppService appService;

    /**
     * 保存对话历史记录
     * AI对话前后都要保存，即使调用AI报错，也要保存
     *
     * @param text
     * @param appId
     * @param userId
     * @param messageType
     * @return
     */
    @Override
    public boolean saveChatHistory(String text, Long appId, Long userId, String messageType) {
        ChatHistory chatHistory = ChatHistory.builder()
                .appId(appId)
                .userId(userId)
                .messageType(messageType)
                .message(text).build();
        return save(chatHistory);
    }

    /**
     * 分页查询对话历史
     *
     * @param appId
     * @param pageSize
     * @param localDateTime
     * @param user
     * @return
     */
    @Override
    public Page<ChatHistory> getChatHistoryByPage(Long appId, int pageSize, LocalDateTime localDateTime, User user) {
        //权限校验
        App app = appService.getById(appId);
        ThrowUtils.throwIf(ObjUtil.isEmpty(app), ErrorCode.OPERATION_ERROR, "该应用不存在");
        ThrowUtils.throwIf(!user.getId().equals(app.getUserId()) && !user.getUserRole().equals(UserConstant.ADMIN_ROLE), ErrorCode.NO_AUTH_ERROR);

        //分页查询 createTime作为游标
        //select .... where appId = xxxx and createTime < xxxx limit 10
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("appId", appId);
        if (ObjUtil.isNotEmpty(localDateTime)) {
            queryWrapper.lt("createTime", localDateTime);
        }

        return this.page(Page.of(1, pageSize), queryWrapper);
    }

    /**
     * 分页查询对话历史(管理员)
     *
     * @param chatHistoryQueryRequest
     * @return
     */
    @Override
    public Page<ChatHistory> getChatHistoryByPage4Admin(ChatHistoryQueryRequest chatHistoryQueryRequest) {
        QueryWrapper queryWrapper = this.makeQueryWrapper(chatHistoryQueryRequest);
        return this.page(Page.of(chatHistoryQueryRequest.getPageNum(), chatHistoryQueryRequest.getPageSize()), queryWrapper);
    }

    /**
     * 从数据库加载对话记忆到redis中
     *
     * @param appId
     * @param messageWindowChatMemory
     * @param count
     */
    @Override
    public void ChatHisD2Memory(long appId, MessageWindowChatMemory messageWindowChatMemory, int count) {
        //从数据库中查询对应条数的对话记忆
        QueryWrapper queryWrapper = new QueryWrapper().eq("appId", appId).orderBy("createTime", true).limit(1, count);
        List<ChatHistory> chatHistories = list(queryWrapper);
        if (CollUtil.isEmpty(chatHistories)) {
            log.info("当前appId:{},没有对话记忆！", appId);
            return;
        }
        int total = 0;
        //先清理messageWindowChatMemory中的历史值。
        messageWindowChatMemory.clear();
        for (ChatHistory chatHistory : chatHistories) {
            //保存时要区分是用户消息还是AI消息
            if (chatHistory.getMessageType().equals(ChatHistoryMessageTypeEnum.AI.getValue())) {
                messageWindowChatMemory.add(AiMessage.from(chatHistory.getMessage()));
            } else if (chatHistory.getMessageType().equals(ChatHistoryMessageTypeEnum.USER.getValue())) {
                messageWindowChatMemory.add(UserMessage.from(chatHistory.getMessage()));
            }
            total++;
        }
        log.info("当前appId:{},共加载了:{}条历史消息", appId, total);
    }

    /**
     * 制作查询条件，用于分页查询
     *
     * @param chatHistoryQueryRequest
     * @return
     */
    private QueryWrapper makeQueryWrapper(ChatHistoryQueryRequest chatHistoryQueryRequest) {
        Long id = chatHistoryQueryRequest.getId();
        String message = chatHistoryQueryRequest.getMessage();
        String messageType = chatHistoryQueryRequest.getMessageType();
        Long appId = chatHistoryQueryRequest.getAppId();
        Long userId = chatHistoryQueryRequest.getUserId();
        LocalDateTime lastCreateTime = chatHistoryQueryRequest.getLastCreateTime();

        String sortField = chatHistoryQueryRequest.getSortField();
        String sortOrder = chatHistoryQueryRequest.getSortOrder();

        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", id);
        queryWrapper.eq("appId", appId);
        queryWrapper.eq("userId", userId);
        queryWrapper.eq("messageType", messageType);
        queryWrapper.like("message", message);

        //游标查询条件
        if (ObjUtil.isNotEmpty(lastCreateTime)) {
            queryWrapper.lt("createTime", lastCreateTime);
        }
        if (StrUtil.isNotEmpty(sortField)) {
            queryWrapper.orderBy(sortField, "ascend".equals(sortOrder));
        } else {
            queryWrapper.orderBy("createTime", false);
        }


        return queryWrapper;
    }
}
